/**
 * Copyright 2020 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.dbfly.mybatis;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;

import org.apache.ibatis.builder.IncompleteElementException;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
import org.apache.ibatis.builder.annotation.MethodResolver;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;

import com.jianggujin.dbfly.util.JBeanUtils;
import com.jianggujin.dbfly.util.JStringUtils;

public class JMapperAnnotationBuilder extends MapperAnnotationBuilder {

    private final Configuration configuration;
    private final MapperBuilderAssistant assistantCopy;
    private final Class<?> type;

    public JMapperAnnotationBuilder(Configuration configuration, Class<?> type) {
        super(configuration, type);
        this.assistantCopy = JBeanUtils.getValue(this, "assistant");
        this.configuration = configuration;
        this.type = type;
    }

    @Override
    public void parse() {
        String resource = type.toString();
        if (!configuration.isResourceLoaded(resource)) {
            loadXmlResource();
            configuration.addLoadedResource(resource);
            assistantCopy.setCurrentNamespace(type.getName());
            JBeanUtils.invokeMethod(this, MapperAnnotationBuilder.class, "parseCache");
            JBeanUtils.invokeMethod(this, MapperAnnotationBuilder.class, "parseCacheRef");
            Method[] methods = type.getMethods();
            for (Method method : methods) {
                try {
                    // issue #237
                    if (!method.isBridge()) {
                        // parseStatement(method);
                        JBeanUtils.invokeMethod(this,
                                JBeanUtils.findMethod(MapperAnnotationBuilder.class, "parseStatement", Method.class),
                                method);
                    }
                } catch (IncompleteElementException e) {
                    configuration.addIncompleteMethod(new MethodResolver(this, method));
                }
            }
        }
        JBeanUtils.invokeMethod(this, MapperAnnotationBuilder.class, "parsePendingMethods");
        this.parseStatementFly();
    }

    /**
     * 解析扩展的{@link MappedStatement}
     */
    private void parseStatementFly() {
        if (configuration instanceof JConfiguration) {
            ((JConfiguration) configuration).getDBFlyConfiguration().getMappedStatementBuilderRegistry()
                    .parse((JConfiguration) configuration, type);
        }
    }

    private void loadXmlResource() {
        // Spring may not know the real resource name so we check a flag
        // to prevent loading again a resource twice
        // this flag is set at XMLMapperBuilder#bindMapperForNamespace
        if (!configuration.isResourceLoaded(JStringUtils.format("namespace:{}", type.getName()))) {
            String xmlResource = JStringUtils.format("{}.xml", type.getName().replace('.', '/'));
            InputStream inputStream = null;
            try {
                inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
            } catch (IOException e) {
                // ignore, resource is not required
            }
            if (inputStream != null) {
                JXMLMapperBuilder xmlParser = new JXMLMapperBuilder(inputStream, assistantCopy.getConfiguration(),
                        xmlResource, configuration.getSqlFragments(), type.getName());
                xmlParser.parse();
            }
        }
    }
}
